package com.qdxwx.payment.wxpay;

import com.qdxwx.payment.wxpay.httpclient.WechatPayHttpClientBuilder;
import com.qdxwx.payment.wxpay.httpclient.auth.PrivateKeySigner;
import com.qdxwx.payment.wxpay.httpclient.auth.ScheduledUpdateCertificatesVerifier;
import com.qdxwx.payment.wxpay.httpclient.auth.WechatPay2Credentials;
import com.qdxwx.payment.wxpay.httpclient.auth.WechatPay2Validator;
import com.qdxwx.payment.wxpay.httpclient.util.PemUtil;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.util.Map;

/**
 * @author ZhiYong
 * @updateTime 2021/12/21
 * @description WxPay(v3版本)
 */
public class WxPayRequest implements AutoCloseable {

    private static final Logger logger = LoggerFactory.getLogger(WxPayRequest.class);

    private final CloseableHttpClient httpClientSSL;

    public WxPayRequest(Map<String, Object> payConfig) {
        if (payConfig.get("privateKey") == null || payConfig.get("serialNo") == null) {
            throw new RuntimeException("wx pay privateKey or serialNo not setting!");
        }
        try {
            PrivateKey privateKey = PemUtil.loadPrivateKey((String) payConfig.get("privateKey"));
            ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(
                    new WechatPay2Credentials((String) payConfig.get("mchId"), new PrivateKeySigner((String) payConfig.get("serialNo"), privateKey)),
                    payConfig.get("apiKey").toString().getBytes(StandardCharsets.UTF_8));

            WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                    .withMerchant((String) payConfig.get("mchId"), (String) payConfig.get("serialNo"), privateKey)
                    .withValidator(new WechatPay2Validator(verifier));
            //.withWechatPay(wechatpayCertificates);
            // 接下来，你仍然可以通过builder设置各种参数，来配置你的HttpClient
            // 通过WechatPayHttpClientBuilder构造的HttpClient，会自动的处理签名和验签
            this.httpClientSSL = builder.build();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public String get(String url) {
        return get(url, null);
    }

    public String get(String url, Map<String, String> queryMap) {

        HttpGet request = new HttpGet(buildUrl(url, queryMap));
        request.addHeader("Accept", "application/json");
        request.addHeader("Content-type", "application/json; charset=utf-8");
        try {
            CloseableHttpResponse httpResponse = this.httpClientSSL.execute(request);
            if (httpResponse != null) {
                HttpEntity entity = httpResponse.getEntity();
                String resp = EntityUtils.toString(entity, "utf-8");
                EntityUtils.consume(entity);
                return resp;
            }
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        return null;
    }

    /**
     * Post String
     *
     * @param url         地址
     * @param queryString 参数
     * @return CloseableHttpResponse
     */

    public String post(String url, String queryString) {
        HttpPost request = new HttpPost(url);
        request.addHeader("Accept", "application/json");
        request.addHeader("Content-type", "application/json; charset=utf-8");
        if (queryString != null) {
            request.setEntity(new StringEntity(queryString, "utf-8"));
        }
        try {
            CloseableHttpResponse httpResponse = this.httpClientSSL.execute(request);
            if (httpResponse != null) {
                HttpEntity entity = httpResponse.getEntity();
                String resp = EntityUtils.toString(entity, "utf-8");
                EntityUtils.consume(entity);
                return resp;
            }
        } catch (Exception ex) {
            logger.error(ex.getMessage());
        }
        return null;
    }

    public String buildUrl(String url, Map<String, String> queryMap) {
        return buildUrl(url, toQueryString(queryMap));
    }

    public String buildUrl(String url, String queryString) {
        StringBuilder sbUrl = new StringBuilder(url);
        if (null != queryString) {
            if (queryString.substring(0, 1).contains("&")) {
                queryString = queryString.substring(1);
            }
            sbUrl.append("?").append(queryString);
        }
        return sbUrl.toString();
    }

    public String toQueryString(Map<String, String> queryMap) {
        if (null == queryMap) return null;
        StringBuilder sbQuery = new StringBuilder();
        for (Map.Entry<String, String> query : queryMap.entrySet()) {
            if (0 < sbQuery.length()) {
                sbQuery.append("&");
            }
            sbQuery.append(query.getKey());
            sbQuery.append("=");
            sbQuery.append(query.getValue());
        }
        return sbQuery.toString();
    }

    @Override
    public void close() throws Exception {
        if (this.httpClientSSL != null) {
            this.httpClientSSL.close();
        }
    }
}
